﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Yto.Common.Dependency;
using Yto.Common.Extensions;
using Yto.Common.Configuration;
using Castle.Core.Logging;

namespace Yto.Modules
{
    public abstract class BaseModule
    {
        protected internal IStartupConfiguration Configuration { get; internal set; }

        protected internal ICtnManager CtnManager { get; set; }

        public virtual void BeforeInitialize() { }

        public virtual void Initialize() { }

        public virtual void AfterInitialize() { }

        public static bool IsInheritBase(Type type)
        {
            var typeInfo = type.GetTypeInfo();
            return typeInfo.IsClass && 
                !typeInfo.IsAbstract && 
                !typeInfo.IsGenericType &&
                typeof(BaseModule).IsAssignableFrom(type);
        }

        public static List<Type> FindDependenies(Type type)
        {
            if (!IsInheritBase(type))
            {
                throw new Exception($"{type.AssemblyQualifiedName} is not a subclass of {nameof(BaseModule)}");
            }
            var list = new List<Type>();

            //if (type.GetTypeInfo().IsDefined(typeof(DependsAttribute),true))
            if (type.IsDefined(typeof(DependsAttribute),true))
            {
                var dependencies = type.GetCustomAttributes<DependsAttribute>();
                foreach(var item in dependencies)
                {
                    foreach(var module in item.DependedTypes)
                    {
                        list.Add(module);
                    }
                }
            }
            return list;
        }

        public static List<Type> GetAllDependecy(Type type)
        {
            var list = new List<Type>();
            AddItems(list, type);
            list.AddNotContained(typeof(KernelModule));
            return list;
        }

        private static void AddItems(List<Type> list, Type type)
        {
            if (!IsInheritBase(type))
            {
                throw new Exception($"{type.AssemblyQualifiedName} is not a subclass of {nameof(BaseModule)}");
            }

            if (list.Contains(type))
            {
                return;
            }

            list.Add(type);
            var dependencies = FindDependenies(type);
            foreach(var item in dependencies)
            {
                AddItems(list, item);
            }
        }


        public ILogger Logger { get; set; }

        protected BaseModule()
        {
            Logger = NullLogger.Instance;
        }
    }
}
